/*
 * Tranquil Java Integrated Development Environment
 *
 * The GNU General Public License Version 3
 *
 * Copyright (C) 2021 Autumn Lamonte
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Autumn Lamonte [AutumnWalksTheLake@gmail.com] ⚧ Trans Liberation Now
 * @version 1
 */
package tjide.ui;

import java.io.IOException;

import gjexer.TExceptionDialog;
import gjexer.TWidget;
import gjexer.bits.CellAttributes;
import gjexer.bits.StringUtils;
import gjexer.event.TKeypressEvent;
import gjexer.event.TMouseEvent;
import static gjexer.TKeypress.*;

import tjide.project.FileTarget;
import tjide.project.Target;
import tjide.project.Project;

/**
 * Message is a clickable item in the MessageWindow.
 */
public class Message extends TWidget {

    // ------------------------------------------------------------------------
    // Variables --------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * The message type.
     */
    public enum Type {

        /**
         * An info message.
         */
        INFO,

        /**
         * A warning message.
         */
        WARNING,

        /**
         * An error message.
         */
        ERROR,
    };

    /**
     * The type of message.
     */
    private Type type;

    /**
     * The target associated with this message.
     */
    private Target target;

    /**
     * The line number that generated this message.
     */
    private int line;

    /**
     * The column number that generated this message.
     */
    private int column;

    /**
     * The post-translated message text.
     */
    private String [] lines;

    /**
     * Left column of the message, for scrolling.  0 is the left-most column.
     */
    private int left = 0;

    // ------------------------------------------------------------------------
    // Constructors -----------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Public constructor.
     *
     * @param parent the window this message will be on
     * @param type the message type
     * @param target the target associated with this message
     * @param line the line number that generated this message
     * @param column the column number that generated this message
     * @param message the post-translated message text
     */
    public Message(final MessageWindow parent, final Type type,
        final Target target, final int line, final int column,
        final String message) {

        // Message is a weird widget.  It is created outside the UI thread by
        // the compiler/builder threads, added to a non-UI list, and then
        // added to MessageWindow in MessageWindow.draw().
        super(null, 0, 0, parent.getWidth() - 2, 1);

        this.type       = type;
        this.target     = target;
        this.line       = line;
        this.column     = column;
        this.lines      = message.split("\n");

        setHeight(lines.length);
    }

    // ------------------------------------------------------------------------
    // Event handlers ---------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Switch to the internal editor at this line and column position.
     *
     * @return true if successful
     */
    public boolean switchToEditor() {
        if ((target == null) || (line < 0) || (column < 0)) {
            return false;
        }
        if (!(target instanceof FileTarget)) {
            return false;
        }

        TranquilApplication app = (TranquilApplication) getApplication();
        InternalEditorWindow editor;
        editor = app.findInternalEditor((FileTarget) target);

        if ((editor == null) && (app.useExternalEditor == false)) {
            Project project = app.getProject();

            // Get this file open in an internal editor.
            for (Target t: project.getTargets()) {
                if (t == target) {
                    try {
                        editor = app.openInternalEditor(project,
                            (FileTarget) t);
                        break;
                    } catch (IOException e) {
                        new TExceptionDialog(app, e);
                    }
                }
            }
        }

        /*
        System.err.println("onDoubleClick() target " + target +
            " editor " + editor);
        */
        if (editor != null) {
            editor.setEditingPositionNumber(line, column);
            editor.activate();
            return true;
        }

        return false;
    }

    /**
     * Handle keystrokes.
     *
     * @param keypress keystroke event
     */
    @Override
    public void onKeypress(final TKeypressEvent keypress) {
        if (keypress.equals(kbEnter)) {
            switchToEditor();
            return;
        }
    }

    /**
     * Method that subclasses can override to handle mouse button
     * double-clicks.
     *
     * @param mouse mouse button event
     */
    @Override
    public void onMouseDoubleClick(final TMouseEvent mouse) {
        switchToEditor();
    }

    // ------------------------------------------------------------------------
    // TWidget ----------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Draw the message.
     */
    @Override
    public void draw() {
        CellAttributes color = null;
        if (type == Type.INFO) {
            if (isActive()) {
                color = getTheme().getColor("messageWindow.info.selected");
            } else {
                color = getTheme().getColor("messageWindow.info");
            }
        } else if (type == Type.WARNING) {
            if (isActive()) {
                color = getTheme().getColor("messageWindow.warning.selected");
            } else {
                color = getTheme().getColor("messageWindow.warning");
            }
        } else {
            if (isActive()) {
                color = getTheme().getColor("messageWindow.error.selected");
            } else {
                color = getTheme().getColor("messageWindow.error");
            }
        }
        hLineXY(0, 0, getWindow().getWidth() - 2, ' ', color);
        int len = getDisplayLength();
        if (left < len) {
            int maxLength = getWindow().getWidth() - 2;
            if (left + maxLength > len) {
                maxLength = len - left;
            }
            for (int i = 0; i < lines.length; i++) {
                if (left < lines[i].length()) {
                    putStringXY(0, i, lines[i].substring(left), color);
                }
            }
        }
    }

    // ------------------------------------------------------------------------
    // Message ----------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Get the message type.
     *
     * @return the message type
     */
    public Type getType() {
        return type;
    }

    /**
     * Get the number of text cells needed to display this message
     *
     * @return the width to display
     */
    public int getDisplayLength() {
        int n = StringUtils.width(lines[0]);
        for (int i = 1; i < lines.length; i++) {
            n = Math.max(n, StringUtils.width(lines[i]));
        }
        return n;
    }

    /**
     * Get the left column to render.
     *
     * @return the left column
     */
    public int getLeft() {
        return left;
    }

    /**
     * Set the left column to render.
     *
     * @param left the new left column
     */
    public void setLeft(final int left) {
        this.left = left;
        if (this.left < 0) {
            this.left = 0;
        }
    }

}
